#include "app_adc.h"

#define ADC_UNINIT  (0x00)
#define ADC_INITED  (0x01)

typedef struct {
    unsigned char inited;
} adc_mgr_t;

static adc_mgr_t sg_adc_mgr = {0x00};
static void app_adc_init(void)
{
    LL_ADC_Reset(ADC1);
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_ADC1);

    if (0 == LL_ADC_IsEnabled(ADC1)) {
        LL_ADC_StartCalibration(ADC1);

        /* Delay between ADC calibration end and ADC enable: minimum 4 ADC Clock cycles */
        while (0 != LL_ADC_IsCalibrationOnGoing(ADC1));
        LL_mDelay(1);
    }

    /* Configure pin 4 as analog input */
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_0, LL_GPIO_MODE_ANALOG);
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_ANALOG);

    LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_NONE);
    LL_ADC_InitTypeDef ADC_InitStruct = {0x00};
    ADC_InitStruct.Clock            = LL_ADC_CLOCK_SYNC_PCLK_DIV4;
    ADC_InitStruct.DataAlignment    = LL_ADC_DATA_ALIGN_RIGHT;
    ADC_InitStruct.LowPowerMode     = LL_ADC_LP_AUTOWAIT;
    ADC_InitStruct.Resolution       = LL_ADC_RESOLUTION_12B;
    LL_ADC_Init(ADC1, &ADC_InitStruct);
    LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_239CYCLES_5);

    LL_ADC_REG_InitTypeDef ADC_REG_InitType = {0x00};
    ADC_REG_InitType.ContinuousMode     = LL_ADC_REG_CONV_SINGLE;
    ADC_REG_InitType.DMATransfer        = LL_ADC_REG_DMA_TRANSFER_NONE;
    ADC_REG_InitType.Overrun            = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
    ADC_REG_InitType.SequencerDiscont   = LL_ADC_REG_SEQ_DISCONT_DISABLE;
    ADC_REG_InitType.TriggerSource      = LL_ADC_REG_TRIG_SOFTWARE;
    LL_ADC_REG_Init(ADC1,&ADC_REG_InitType);
    sg_adc_mgr.inited = ADC_INITED;
}

int app_adc_convert(unsigned int channel)
{
    if (sg_adc_mgr.inited == ADC_UNINIT) {
        app_adc_init();
    }
    WRITE_REG(ADC1->CHSELR,0);
    LL_ADC_REG_SetSequencerChAdd(ADC1, channel);
    LL_ADC_Enable(ADC1);
    /* ADC stabilization time, minimum 8 ADC Clock cycles */
    LL_mDelay(1);

    LL_ADC_REG_StartConversion(ADC1);
    while(LL_ADC_IsActiveFlag_EOC(ADC1)==0);
    LL_ADC_ClearFlag_EOC(ADC1);
    int value = LL_ADC_REG_ReadConversionData12(ADC1);
    WRITE_REG(ADC1->CHSELR,0);
    return value;
}

void app_adc_closed(void)
{
    if (sg_adc_mgr.inited == ADC_INITED) {
        LL_ADC_Disable(ADC1);
    }
    sg_adc_mgr.inited = ADC_UNINIT;
}